package com.settlement.system.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.settlement.system.common.base.IBaseEnum;
import com.settlement.system.common.constant.SystemConstants;
import com.settlement.system.common.enums.PlatFormKeyEnum;
import com.settlement.system.common.util.DateUtils;
import com.settlement.system.common.util.StringUtils;
import com.settlement.system.mapper.*;
import com.settlement.system.model.entity.*;
import com.settlement.system.model.query.BillPageQuery;
import com.settlement.system.model.query.FinanceReportQuery;
import com.settlement.system.model.vo.DateItem;
import com.settlement.system.model.vo.FinanceReportVo;
import com.settlement.system.model.vo.SysAccountingProjectVO;
import com.settlement.system.service.*;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class FinanceReportServiceImpl implements FinanceReportService {

    private final Logger logger = LoggerFactory.getLogger(FinanceReportServiceImpl.class);

    private final SysBalanceService sysBalanceService;

    private final SysBillMapper sysBillMapper;

    private final SysAccountingProjectService sysAccountingProjectService;

    private final SysStoreService sysStoreService;

    private final SysPlatformService sysPlatformService;

    private final JdFundFlowMapper jdFundFlowMapper;

    private final SphFundFlowMapper sphFundFlowMapper;

    private final TmFundFlowMapper tmFundFlowMapper;

    private final WdFundFlowMapper wdFundFlowMapper;

    private final WmFundFlowMapper wmFundFlowMapper;

    private final XhsSaleDetailMapper xhsSaleDetailMapper;

    private final XhsWechatDetailMapper xhsWechatDetailMapper;

    private final YzFundFlowMapper yzFundFlowMapper;

    private final SysBillDateLinkService sysBillDateLinkService;

    private final RedisTemplate redisTemplate;

    @Override
    public List<FinanceReportVo> listFinanceReport(FinanceReportQuery queryParams) {
        List<FinanceReportVo> voList = new ArrayList<>();
        String startDate = queryParams.getStartDate();
        String endDate = queryParams.getEndDate();
        String platformKeyText = StringUtils.hasText(queryParams.getPlatformKey()) ? queryParams.getPlatformKey() : "";
        String strStoreId = Objects.nonNull(queryParams.getStoreId()) ? queryParams.getStoreId().toString() : "";
        String key = SystemConstants.FUNDS_DAILY_REPORT_KEY.formatted(startDate.replaceAll("-", "") +"-"+ endDate.replaceAll("-", ""), platformKeyText, strStoreId);
        Object value = redisTemplate.opsForValue().get(key);
        if (Objects.nonNull(value)) {
            voList = (List<FinanceReportVo>) value;
            if (voList.size() > 0) {
                return voList;
            }
        }
        String platformKey = queryParams.getPlatformKey();
        Long storeId = queryParams.getStoreId();
        LocalDateTime start;
        LocalDateTime end;
        if (StringUtils.hasText(startDate) && StringUtils.hasText(endDate)) {
            start = DateUtils.convertStringToLocalDateTime(startDate);
            end = DateUtils.convertStringToLocalDateTime(endDate).plusDays(1);
        }else{
            // 查询周期（开始日期、截止日期）的默认日期：每月2日前（上月1日 到 T-1日）；每月2日后，含2日（本月1日 到 T-1日）
            if (LocalDateTime.now().getDayOfMonth() < 2) {
                start = LocalDateTime.now().minusMonths(1).minusDays(LocalDateTime.now().getDayOfMonth() - 1).toLocalDate().atStartOfDay();
                end = LocalDateTime.now().minusDays(1).toLocalDate().atStartOfDay();
            } else {
                start = LocalDateTime.now().minusDays(LocalDateTime.now().getDayOfMonth() - 1).toLocalDate().atStartOfDay();
                end = LocalDateTime.now().minusDays(1).toLocalDate().atStartOfDay();
            }
        }
        LocalDateTime balanceStartDate = start;
        LocalDateTime balanceEndDate = end;
        List<DateItem> dateItemList = new ArrayList<>();
        // 组装日期列表
        while (start.plusDays(1).isBefore(end)) {
            DateItem dateItem = new DateItem();
            dateItem.setStartTime(start);
            dateItem.setEndTime(start.plusDays(1));
            dateItemList.add(dateItem);
            start = start.plusDays(1);
        }
        // 加上最后一个时间段
        dateItemList.add(new DateItem(start, end));
        // 按照出账日期查询账单
        List<SysBillDateLink> filterBillDateLinkList;
        List<SysBillDateLink> billDateLinkList = sysBillDateLinkService.list();
        List<String> tableNameList = new ArrayList<>();
        // 循环日期列表，查询每个出账日期范围所在的账单月份
        for (DateItem dateItem : dateItemList) {
            String billMonth = DateUtils.formatDate(dateItem.getStartTime());
            filterBillDateLinkList = billDateLinkList.stream().filter(item -> Objects.equals(item.getBillDateMonth(), billMonth)).toList();
            if (filterBillDateLinkList.size() > 0) {
                for (SysBillDateLink sysBillDateLink : filterBillDateLinkList) {
                    if (!tableNameList.contains(sysBillDateLink.getTableName())) {
                        tableNameList.add(sysBillDateLink.getTableName());
                    }
                }
            }
        }
        // 账单记账项目
        SysAccountingProjectVO sysAccountingProjectVo;
        List<SysAccountingProject> accountingProjectList = sysAccountingProjectService.list();
        List<SysAccountingProjectVO> sysAccountingProjectVoList = new ArrayList<>();
        for (SysAccountingProject sysAccountingProject : accountingProjectList) {
            sysAccountingProjectVo = new SysAccountingProjectVO();
            BeanUtils.copyProperties(sysAccountingProject, sysAccountingProjectVo, "accessory", "otherAccessory");
            if (StringUtils.hasText(sysAccountingProject.getFundingProjectsStr())) {
                sysAccountingProjectVo.setFundingProjects(JSONObject.parseObject(sysAccountingProject.getFundingProjectsStr(), Map.class));
            }
            sysAccountingProjectVoList.add(sysAccountingProjectVo);
        }
        // 查询店铺
        List<SysStore> storeList = sysStoreService.list(new LambdaQueryWrapper<SysStore>().eq(StringUtils.hasText(platformKey), SysStore::getStoreKey, platformKey).eq(Objects.nonNull(storeId), SysStore::getId, storeId));
        if (storeList.size() == 0) {
            return voList;
        }
        // 按照storeKey排序
        storeList.sort(Comparator.comparing(SysStore::getStoreKey));
        FinanceReportVo vo;
        SysPlatform sysPlatform;
        List<SysAccountingProjectVO> storeAccountProjectList;
        List<SysBill> storeBillList;
        // 按照结束日期(拼多多、抖音)查询余额
        List<SysBalance> balanceList = sysBalanceService.list(new LambdaQueryWrapper<SysBalance>().ge(SysBalance::getBillDate, balanceStartDate.toLocalDate()).lt(SysBalance::getBillDate, balanceEndDate.toLocalDate()));
        // 标准账单
        BillPageQuery billQueryParams = new BillPageQuery();
        logger.info("tableNameList:%s".formatted(tableNameList));
        for (String tableName : tableNameList) {
            if (!StringUtils.hasText(sysBillMapper.existTable(tableName))) {
                continue;
            }
            for (DateItem dateItem : dateItemList) {
                Page<SysBill> page = new Page<>(1, 3000);
                billQueryParams.setTableNameList(Collections.singletonList(tableName));
                billQueryParams.setStartBillDate(dateItem.getStartTime());
                billQueryParams.setEndBillDate(dateItem.getEndTime());
                billQueryParams.setStoreIdList(storeList.stream().map(SysStore::getId).collect(Collectors.toList()));
                sysBillMapper.getPage(page, billQueryParams);
                logger.info("查询表【%s】，查询日期范围：【%s】到【%s】,共【%s】条，共【%s】页".formatted(tableName, dateItem.getStartTime(), dateItem.getEndTime(), page.getTotal(), page.getPages()));
                if (page.getRecords().size() > 0) {
                    while (page.getRecords().size() > 0) {
                        // 循环所有店铺
                        for (SysStore sysStore : storeList) {
                            // 按照店铺过滤
                            vo = voList.stream().filter(item -> Objects.equals(item.getStoreId(), sysStore.getId())).findFirst().orElse(null);
                            if (Objects.isNull(vo)) {
                                vo = new FinanceReportVo();
                            }
                            storeBillList = page.getRecords().stream().filter(bill -> Objects.equals(bill.getStoreId(), sysStore.getId())).toList();
                            storeAccountProjectList = new ArrayList<>();
                            // 平台名称
                            sysPlatform = sysPlatformService.getByPlatformKey(sysStore.getStoreKey());
                            // 店铺名称
                            vo.setStoreId(sysStore.getId());
                            vo.setStoreName(sysStore.getCommercePlatformStoreName());
                            if (Objects.nonNull(sysPlatform)) {
                                String reconciliationSystemCode = sysPlatform.getReconciliationSystemCode();
                                vo.setPlatformName(sysPlatform.getReconciliationSystemName());
                                storeAccountProjectList = sysAccountingProjectVoList.stream().filter(item -> Objects.equals(item.getBillSystemPlatformCode(), reconciliationSystemCode)).toList();
                            }
                            PlatFormKeyEnum platFormKeyEnum = IBaseEnum.getEnumByValue(sysStore.getStoreKey(), PlatFormKeyEnum.class);
                            if (Objects.nonNull(platFormKeyEnum)) {
                                switch (platFormKeyEnum) {
                                    case JD ->
                                            fillJdVo("京东资金流水", vo, sysStore.getId(), balanceEndDate, dateItemList, storeAccountProjectList, storeBillList);
                                    case PDD ->
                                            fillPddVo("拼多多资金流水", vo, sysStore.getId(), balanceEndDate, storeAccountProjectList, storeBillList, balanceList);
                                    case SPH ->
                                            fillSphVo("视频号资金流水", vo, sysStore.getId(), balanceEndDate, dateItemList, storeAccountProjectList, storeBillList);
                                    case TM ->
                                            fillTmVo("天猫资金流水", vo, sysStore.getId(), balanceEndDate, dateItemList, storeAccountProjectList, storeBillList);
                                    case WD ->
                                            fillWdVo("微店资金流水", vo, sysStore.getId(), balanceEndDate, dateItemList, storeAccountProjectList, storeBillList);
                                    case WM ->
                                            fillWmVo("微盟资金流水", vo, sysStore.getId(), balanceEndDate, dateItemList, storeAccountProjectList, storeBillList);
                                    case XHS ->
                                            fillXhsVo("小红书货款明细,小红书微信明细", vo, sysStore.getId(), balanceEndDate, dateItemList, storeAccountProjectList, storeBillList);
                                    case YZ ->
                                            fillYzVo("有赞资金流水", vo, sysStore.getId(), balanceEndDate, dateItemList, storeAccountProjectList, storeBillList);
                                    case DY ->
                                            fillDyVo("抖音资金流水", vo, sysStore.getId(), balanceEndDate, storeAccountProjectList, storeBillList, balanceList);
                                    default -> {
                                    }
                                }
                            }
                            // 删除已存在的店铺数据
                            voList.removeIf(item -> Objects.equals(item.getStoreId(), sysStore.getId()));
                            // 重新添加
                            voList.add(vo);
                        }
                        // 查询下一页
                        page.setCurrent(page.getCurrent() + 1);
                        logger.info("正在查询第【%s】页".formatted(page.getCurrent()));
                        sysBillMapper.getPage(page, billQueryParams);
                    }
                }else{
                    // 如果没有数据，添加一条默认的店铺数据
                    for (SysStore sysStore : storeList) {
                        // 按照店铺过滤
                        vo = voList.stream().filter(item -> Objects.equals(item.getStoreId(), sysStore.getId())).findFirst().orElse(null);
                        if (Objects.isNull(vo)) {
                            vo = new FinanceReportVo();
                        }
                        // 平台名称
                        sysPlatform = sysPlatformService.getByPlatformKey(sysStore.getStoreKey());
                        // 店铺名称
                        vo.setStoreId(sysStore.getId());
                        vo.setStoreName(sysStore.getCommercePlatformStoreName());
                        if (Objects.nonNull(sysPlatform)) {
                            vo.setPlatformName(sysPlatform.getReconciliationSystemName());
                        }
                        // 删除已存在的店铺数据
                        voList.removeIf(item -> Objects.equals(item.getStoreId(), sysStore.getId()));
                        // 重新添加
                        voList.add(vo);
                    }
                }

            }
        }
        // 把数据保存到redis，设置5分钟有效期
        redisTemplate.opsForValue().set(key, voList, 5, TimeUnit.MINUTES);
        return voList;
    }

    /**
     * 填充京东相关数据
     * @param orderType          单据来源
     * @param vo                 数据项
     * @param storeId            店铺id
     * @param endDate            结束日期
     * @param dateItemList       日期拆分列表
     * @param accountProjectList 当前店铺的记账项目配置
     * @param billList           当前店铺的账单
     */
    private void fillJdVo(String orderType, FinanceReportVo vo, Long storeId, LocalDateTime endDate, List<DateItem> dateItemList, List<SysAccountingProjectVO> accountProjectList, List<SysBill> billList) {
        // 查询余额
        JdFundFlow query = new JdFundFlow();
        String tableName;
        // dateItemList反转
        dateItemList = dateItemList.stream().sorted(Comparator.comparing(DateItem::getStartTime).reversed()).collect(Collectors.toList());
        // 余额只需要找一次即可
        if (!vo.getFindBalance()) {
            for (DateItem dateItem : dateItemList) {
                tableName = "jd_fund_flow_%s".formatted(DateUtils.formatDate(dateItem.getStartTime()));
                if (!StringUtils.hasText(jdFundFlowMapper.existTable(tableName))) {
                    continue;
                }
                query.setStoreId(storeId);
                query.setTableName(tableName);
                query.setStartDate(dateItem.getStartTime());
                query.setEndDate(dateItem.getEndTime());
                List<JdFundFlow> jdFundFlowList = jdFundFlowMapper.getNewestBalance(query);
                if (jdFundFlowList.size() > 0) {
                    vo.setBalanceAmount(jdFundFlowList.get(0).getBalance());
                    break;
                }
            }
        }
        vo.setFindBalance(true);
        // 如果没有配置记账项目，直接返回
        if (accountProjectList.size() == 0) {
            return;
        }
        fillBillData(orderType, vo, endDate, accountProjectList, billList);
    }

    /**
     * 填充拼多多相关数据
     * @param orderType          单据来源
     * @param vo                 数据项
     * @param storeId            店铺id
     * @param endDate            结束日期
     * @param accountProjectList 当前店铺的记账项目配置
     * @param billList           当前店铺的账单
     */
    private void fillPddVo(String orderType, FinanceReportVo vo, Long storeId, LocalDateTime endDate, List<SysAccountingProjectVO> accountProjectList, List<SysBill> billList, List<SysBalance> balanceList) {
        // 余额只需要找一次即可
        if (!vo.getFindBalance()) {
            // 获取余额余额
            List<SysBalance> balances = balanceList.stream().filter(item -> Objects.equals(item.getStoreId(), storeId)).toList();
            if (balances.size() > 0) {
                // 按照账单日期倒序排序
                balances.stream().max(Comparator.comparing(SysBalance::getBillDate)).ifPresent(item -> {
                    vo.setBalanceAmount(item.getBalanceAmount());
                });
            }
        }
        vo.setFindBalance(true);
        // 如果没有配置记账项目，直接返回
        if (accountProjectList.size() == 0) {
            return;
        }
        fillBillData(orderType, vo, endDate, accountProjectList, billList);
    }

    /**
     * 填充视频号相关数据
     * @param orderType          单据来源
     * @param vo                 数据项
     * @param storeId            店铺id
     * @param endDate            结束日期
     * @param dateItemList       日期拆分列表
     * @param accountProjectList 当前店铺的记账项目配置
     * @param billList           当前店铺的账单
     */
    private void fillSphVo(String orderType, FinanceReportVo vo, Long storeId, LocalDateTime endDate, List<DateItem> dateItemList, List<SysAccountingProjectVO> accountProjectList, List<SysBill> billList) {
        // 余额只需要找一次即可
        if (!vo.getFindBalance()) {
            // 查询余额
            SphFundFlow query = new SphFundFlow();
            String tableName;
            // dateItemList反转
            dateItemList = dateItemList.stream().sorted(Comparator.comparing(DateItem::getStartTime).reversed()).collect(Collectors.toList());
            for (DateItem dateItem : dateItemList) {
                tableName = "sph_fund_flow_%s".formatted(DateUtils.formatDate(dateItem.getStartTime()));
                if (!StringUtils.hasText(sphFundFlowMapper.existTable(tableName))) {
                    continue;
                }
                query.setStoreId(storeId);
                query.setTableName(tableName);
                query.setStartBillTime(dateItem.getStartTime());
                query.setEndBillTime(dateItem.getEndTime());
                List<SphFundFlow> sphFundFlowList = sphFundFlowMapper.getNewestBalance(query);
                if (sphFundFlowList.size() > 0) {
                    vo.setBalanceAmount(sphFundFlowList.get(0).getBalanceAmount());
                    break;
                }
            }
        }
        vo.setFindBalance(true);
        // 如果没有配置记账项目，直接返回
        if (accountProjectList.size() == 0) {
            return;
        }
        fillBillData(orderType, vo, endDate, accountProjectList, billList);
    }

    /**
     * 填充天猫相关数据
     * @param orderType          单据来源
     * @param vo                 数据项
     * @param storeId            店铺id
     * @param endDate            结束日期
     * @param dateItemList       日期拆分列表
     * @param accountProjectList 当前店铺的记账项目配置
     * @param billList           当前店铺的账单
     */
    private void fillTmVo(String orderType, FinanceReportVo vo, Long storeId, LocalDateTime endDate, List<DateItem> dateItemList, List<SysAccountingProjectVO> accountProjectList, List<SysBill> billList) {
        // 余额只需要找一次即可
        if (!vo.getFindBalance()) {
            // 查询余额
            TmFundFlow query = new TmFundFlow();
            String tableName;
            // dateItemList反转
            dateItemList = dateItemList.stream().sorted(Comparator.comparing(DateItem::getStartTime).reversed()).collect(Collectors.toList());
            for (DateItem dateItem : dateItemList) {
                tableName = "tm_fund_flow_%s".formatted(DateUtils.formatDate(dateItem.getStartTime()));
                if (!StringUtils.hasText(tmFundFlowMapper.existTable(tableName))) {
                    continue;
                }
                query.setStoreId(storeId);
                query.setTableName(tableName);
                query.setStartOrderTime(dateItem.getStartTime());
                query.setEndOrderTime(dateItem.getEndTime());
                List<TmFundFlow> tmFundFlowList = tmFundFlowMapper.getNewestBalance(query);
                if (tmFundFlowList.size() > 0) {
                    vo.setBalanceAmount(tmFundFlowList.get(0).getBalance());
                    break;
                }
            }
        }
        vo.setFindBalance(true);
        // 如果没有配置记账项目，直接返回
        if (accountProjectList.size() == 0) {
            return;
        }
        fillBillData(orderType, vo, endDate, accountProjectList, billList);
    }

    /**
     * 填充微店相关数据
     * @param orderType          单据来源
     * @param vo                 数据项
     * @param storeId            店铺id
     * @param endDate            结束日期
     * @param dateItemList       日期拆分列表
     * @param accountProjectList 当前店铺的记账项目配置
     * @param billList           当前店铺的账单
     */
    private void fillWdVo(String orderType, FinanceReportVo vo, Long storeId, LocalDateTime endDate, List<DateItem> dateItemList, List<SysAccountingProjectVO> accountProjectList, List<SysBill> billList) {
        // 余额只需要找一次即可
        if (!vo.getFindBalance()) {
            // 查询余额
            WdFundFlow query = new WdFundFlow();
            String tableName;
            // dateItemList反转
            dateItemList = dateItemList.stream().sorted(Comparator.comparing(DateItem::getStartTime).reversed()).collect(Collectors.toList());
            for (DateItem dateItem : dateItemList) {
                tableName = "wd_fund_flow_%s".formatted(DateUtils.formatDate(dateItem.getStartTime()));
                if (!StringUtils.hasText(wdFundFlowMapper.existTable(tableName))) {
                    continue;
                }
                query.setStoreId(storeId);
                query.setTableName(tableName);
                query.setStartBillTime(dateItem.getStartTime());
                query.setEndBillTime(dateItem.getEndTime());
                List<WdFundFlow> wdFundFlowList = wdFundFlowMapper.getNewestBalance(query);
                if (wdFundFlowList.size() > 0) {
                    vo.setBalanceAmount(wdFundFlowList.get(0).getBalanceAmount());
                    break;
                }
            }
        }
        vo.setFindBalance(true);
        // 如果没有配置记账项目，直接返回
        if (accountProjectList.size() == 0) {
            return;
        }
        fillBillData(orderType, vo, endDate, accountProjectList, billList);
    }

    /**
     * 填充微盟相关数据
     * @param orderType          单据来源
     * @param vo                 数据项
     * @param storeId            店铺id
     * @param endDate            结束日期
     * @param dateItemList       日期拆分列表
     * @param accountProjectList 当前店铺的记账项目配置
     * @param billList           当前店铺的账单
     */
    private void fillWmVo(String orderType, FinanceReportVo vo, Long storeId, LocalDateTime endDate, List<DateItem> dateItemList, List<SysAccountingProjectVO> accountProjectList, List<SysBill> billList) {
        // 余额只需要找一次即可
        if (!vo.getFindBalance()) {
            // 查询余额
            WmFundFlow query = new WmFundFlow();
            String tableName;
            // dateItemList反转
            dateItemList = dateItemList.stream().sorted(Comparator.comparing(DateItem::getStartTime).reversed()).collect(Collectors.toList());
            for (DateItem dateItem : dateItemList) {
                tableName = "wm_fund_flow_%s".formatted(DateUtils.formatDate(dateItem.getStartTime()));
                if (!StringUtils.hasText(wmFundFlowMapper.existTable(tableName))) {
                    continue;
                }
                query.setStoreId(storeId);
                query.setTableName(tableName);
                query.setStartBillTime(dateItem.getStartTime());
                query.setEndBillTime(dateItem.getEndTime());
                List<WmFundFlow> wdFundFlowList = wmFundFlowMapper.getNewestBalance(query);
                if (wdFundFlowList.size() > 0) {
                    vo.setBalanceAmount(wdFundFlowList.get(0).getBalanceAmount());
                    break;
                }
            }
        }
        vo.setFindBalance(true);
        // 如果没有配置记账项目，直接返回
        if (accountProjectList.size() == 0) {
            return;
        }
        fillBillData(orderType, vo, endDate, accountProjectList, billList);
    }

    /**
     * 填充小红书相关数据
     * @param orderType          单据来源
     * @param vo                 数据项
     * @param storeId            店铺id
     * @param endDate            结束日期
     * @param dateItemList       日期拆分列表
     * @param accountProjectList 当前店铺的记账项目配置
     * @param billList           当前店铺的账单
     */
    private void fillXhsVo(String orderType, FinanceReportVo vo, Long storeId, LocalDateTime endDate, List<DateItem> dateItemList, List<SysAccountingProjectVO> accountProjectList, List<SysBill> billList) {
        // 余额只需要找一次即可
        if (!vo.getFindBalance()) {
            // 查询余额
            XhsSaleDetail saleQuery = new XhsSaleDetail();
            XhsWechatDetail wechatQuery = new XhsWechatDetail();
            boolean findSaleBalance = false;
            boolean findWechatBalance = false;
            String tableName;
            // dateItemList反转
            dateItemList = dateItemList.stream().sorted(Comparator.comparing(DateItem::getStartTime).reversed()).collect(Collectors.toList());
            for (DateItem dateItem : dateItemList) {
                // 查询货款明细余额
                if (!findSaleBalance) {
                    tableName = "xhs_sale_detail_%s".formatted(DateUtils.formatDate(dateItem.getStartTime()));
                    if (StringUtils.hasText(xhsSaleDetailMapper.existTable(tableName))) {
                        saleQuery.setStoreId(storeId);
                        saleQuery.setTableName(tableName);
                        saleQuery.setStartBillCreateTime(dateItem.getStartTime());
                        saleQuery.setEndBillCreateTime(dateItem.getEndTime());
                        List<XhsSaleDetail> xhsSaleDetailList = xhsSaleDetailMapper.getNewestBalance(saleQuery);
                        if (xhsSaleDetailList.size() > 0) {
                            vo.setBalanceAmount(vo.getBalanceAmount().add(xhsSaleDetailList.get(0).getBalanceAmount()));
                            findSaleBalance = true;
                        }
                    }
                }
                // 查询微信明细余额
                if (!findWechatBalance) {
                    tableName = "xhs_wechat_detail_%s".formatted(DateUtils.formatDate(dateItem.getStartTime()));
                    if (StringUtils.hasText(xhsWechatDetailMapper.existTable(tableName))) {
                        wechatQuery.setStoreId(storeId);
                        wechatQuery.setTableName(tableName);
                        wechatQuery.setStartBillTime(dateItem.getStartTime());
                        wechatQuery.setEndBillTime(dateItem.getEndTime());
                        List<XhsWechatDetail> xhsWechatDetailList = xhsWechatDetailMapper.getNewestBalance(wechatQuery);
                        if (xhsWechatDetailList.size() > 0) {
                            vo.setBalanceAmount(vo.getBalanceAmount().add(xhsWechatDetailList.get(0).getBalanceAmount()));
                            findWechatBalance = true;
                        }
                    }
                }
                // 如果都找到则结束
                if (findSaleBalance && findWechatBalance) {
                    break;
                }
            }
        }
        vo.setFindBalance(true);
        // 如果没有配置记账项目，直接返回
        if (accountProjectList.size() == 0) {
            return;
        }
        fillBillData(orderType, vo, endDate, accountProjectList, billList);
    }

    /**
     * 填充有赞相关数据
     * @param orderType          单据来源
     * @param vo                 数据项
     * @param storeId            店铺id
     * @param endDate            结束日期
     * @param dateItemList       日期拆分列表
     * @param accountProjectList 当前店铺的记账项目配置
     * @param billList           当前店铺的账单
     */
    private void fillYzVo(String orderType, FinanceReportVo vo, Long storeId, LocalDateTime endDate, List<DateItem> dateItemList, List<SysAccountingProjectVO> accountProjectList, List<SysBill> billList) {
        // 余额只需要找一次即可
        if (!vo.getFindBalance()) {

            // 查询余额
            YzFundFlow query = new YzFundFlow();
            String tableName;
            // dateItemList反转
            dateItemList = dateItemList.stream().sorted(Comparator.comparing(DateItem::getStartTime).reversed()).collect(Collectors.toList());
            for (DateItem dateItem : dateItemList) {
                tableName = "yz_fund_flow_%s".formatted(DateUtils.formatDate(dateItem.getStartTime()));
                if (!StringUtils.hasText(yzFundFlowMapper.existTable(tableName))) {
                    continue;
                }
                query.setStoreId(storeId);
                query.setTableName(tableName);
                query.setStartBillTime(dateItem.getStartTime());
                query.setEndBillTime(dateItem.getEndTime());
                List<YzFundFlow> yzFundFlowList = yzFundFlowMapper.getNewestBalance(query);
                if (yzFundFlowList.size() > 0) {
                    vo.setBalanceAmount(yzFundFlowList.get(0).getBalanceAmount());
                    break;
                }
            }
        }
        vo.setFindBalance(true);
        // 如果没有配置记账项目，直接返回
        if (accountProjectList.size() == 0) {
            return;
        }
        fillBillData(orderType, vo, endDate, accountProjectList, billList);
    }

    /**
     * 填充抖音相关数据
     * @param orderType          单据来源
     * @param vo                 数据项
     * @param storeId            店铺id
     * @param endDate            结束日期
     * @param accountProjectList 当前店铺的记账项目配置
     * @param billList           当前店铺的账单
     */
    private void fillDyVo(String orderType, FinanceReportVo vo, Long storeId, LocalDateTime endDate, List<SysAccountingProjectVO> accountProjectList, List<SysBill> billList, List<SysBalance> balanceList) {
        // 余额只需要找一次即可
        if (!vo.getFindBalance()) {
            // 获取余额余额
            List<SysBalance> balances = balanceList.stream().filter(item -> Objects.equals(item.getStoreId(), storeId)).toList();
            if (balances.size() > 0) {
                // 按照账单日期倒序排序
                balances.stream().max(Comparator.comparing(SysBalance::getBillDate)).ifPresent(item -> {
                    vo.setBalanceAmount(item.getBalanceAmount());
                });
            }
        }
        vo.setFindBalance(true);
        // 如果没有配置记账项目，直接返回
        if (accountProjectList.size() == 0) {
            return;
        }
        fillBillData(orderType, vo, endDate, accountProjectList, billList);
    }

    /**
     * 填充账单数据
     * @param orderType          单据来源
     * @param vo                 数据项
     * @param endDate            结束日期
     * @param accountProjectList 记账项目配置
     * @param billList           当前店铺账单数据
     */
    private void fillBillData(String orderType, FinanceReportVo vo, LocalDateTime endDate, List<SysAccountingProjectVO> accountProjectList, List<SysBill> billList) {
        List<String> orderTypeList = Arrays.asList(orderType.split(","));
        List<SysAccountingProjectVO> filterAccountProjectList;
        // 累计提现：取记账项目配置中，资金项目类别2为“提现”的费用项金额进行累计。
        filterAccountProjectList = accountProjectList.stream().filter(item -> item.getFundingProjects().containsKey("资金项目类别2")
                && Objects.nonNull(item.getFundingProjects().get("资金项目类别2"))
                && Objects.equals(item.getFundingProjects().get("资金项目类别2").replaceAll("\\+", "").replaceAll("-", "").strip(), "提现")).toList();
        vo.setCashAmount(vo.getCashAmount().add(sumBillAmountFromFinanceConfig(null, filterAccountProjectList, billList)));
        // 截止日期当天收入：取记账项目配置中来源单据为“orderType”并且实际收支方向为“收入”并且是否参与记账为“参与”的所有费用项的账单金额，并累计
        filterAccountProjectList = accountProjectList.stream().filter(item -> orderTypeList.contains(item.getOrderType()) && Objects.equals(item.getPayType(), "收入") && Objects.equals(item.getAccounting(), "参与")).toList();
        vo.setLastReceiveAmount(vo.getLastReceiveAmount().add(sumBillAmountFromAccountingProject(endDate, filterAccountProjectList, billList)));
        // 累计收入：取记账项目配置中来源单据为“orderType”并且实际收支方向为“收入”并且是否参与记账为“参与”的所有费用项的账单金额，并累计
        vo.setTotalReceiveAmount(vo.getTotalReceiveAmount().add(sumBillAmountFromAccountingProject(null, filterAccountProjectList, billList)));
        // 截止日期当天支出：取记账项目配置中来源单据为“orderType”并且实际收支方向为“支出”并且是否参与记账为“参与”的所有费用项的账单金额，并累计
        filterAccountProjectList = accountProjectList.stream().filter(item -> orderTypeList.contains(item.getOrderType()) && Objects.equals(item.getPayType(), "支出") && Objects.equals(item.getAccounting(), "参与")).toList();
        vo.setLastPayAmount(vo.getLastPayAmount().add(sumBillAmountFromAccountingProject(endDate, filterAccountProjectList, billList)));
        // 累计支出：取记账项目配置中来源单据为“orderType”并且实际收支方向为“支出”并且是否参与记账为“参与”的所有费用项的账单金额，并累计
        vo.setTotalPayAmount(vo.getTotalPayAmount().add(sumBillAmountFromAccountingProject(null, filterAccountProjectList, billList)));
        // 截止日期当天支出其中-退款：取记账项目配置中，资金项目类别2为“退款”的费用项金额进行累计。
        filterAccountProjectList = accountProjectList.stream().filter(item -> item.getFundingProjects().containsKey("资金项目类别2")
                && Objects.nonNull(item.getFundingProjects().get("资金项目类别2"))
                && Objects.equals(item.getFundingProjects().get("资金项目类别2").replaceAll("\\+", "").replaceAll("-", "").strip(), "退款")).toList();
        vo.setLastRefundAmount(vo.getLastRefundAmount().add(sumBillAmountFromFinanceConfig(endDate, filterAccountProjectList, billList)));
        // 累计支出其中-退款
        vo.setTotalRefundAmount(vo.getTotalRefundAmount().add(sumBillAmountFromFinanceConfig(null, filterAccountProjectList, billList)));
        // 截止日期当天支出其中-佣金：取记账项目配置中，资金项目类别2为“佣金”的费用项金额进行累计。
        filterAccountProjectList = accountProjectList.stream().filter(item -> item.getFundingProjects().containsKey("资金项目类别2")
                && Objects.nonNull(item.getFundingProjects().get("资金项目类别2"))
                && Objects.equals(item.getFundingProjects().get("资金项目类别2").replaceAll("\\+", "").replaceAll("-", "").strip(), "佣金")).toList();
        vo.setLastCommission(vo.getLastCommission().add(sumBillAmountFromFinanceConfig(endDate, filterAccountProjectList, billList)));
        // 累计支出其中-佣金
        vo.setTotalCommission(vo.getTotalCommission().add(sumBillAmountFromFinanceConfig(null, filterAccountProjectList, billList)));
        // 截止日期当天支出其中-预充值：取记账项目配置中，资金项目类别2为“预充值”的费用项金额进行累计。
        filterAccountProjectList = accountProjectList.stream().filter(item -> item.getFundingProjects().containsKey("资金项目类别2")
                && Objects.nonNull(item.getFundingProjects().get("资金项目类别2"))
                && Objects.equals(item.getFundingProjects().get("资金项目类别2").replaceAll("\\+", "").replaceAll("-", "").strip(), "预充值")).toList();
        vo.setLastCharge(vo.getLastCharge().add(sumBillAmountFromFinanceConfig(endDate, filterAccountProjectList, billList)));
        // 累计支出其中-预充值
        vo.setTotalCharge(vo.getTotalCharge().add(sumBillAmountFromFinanceConfig(null, filterAccountProjectList, billList)));
        // 截止日期当天支出其中-其他费用：取记账项目配置中，资金项目类别2为“其他费用”的费用项金额进行累计。
        filterAccountProjectList = accountProjectList.stream().filter(item -> item.getFundingProjects().containsKey("资金项目类别2")
                && Objects.nonNull(item.getFundingProjects().get("资金项目类别2"))
                && Objects.equals(item.getFundingProjects().get("资金项目类别2").replaceAll("\\+", "").replaceAll("-", "").strip(), "其他费用")).toList();
        vo.setLastOtherFee(vo.getLastOtherFee().add(sumBillAmountFromFinanceConfig(endDate, filterAccountProjectList, billList)));
        // 累计支出其中-其他费用
        vo.setTotalOtherFee(vo.getTotalOtherFee().add(sumBillAmountFromFinanceConfig(null, filterAccountProjectList, billList)));
    }

    /**
     * 根据资金项目类别配置统计账单金额
     * @param endDate                   截止日期
     * @param filterAccountProjectList  符合条件的记账项目
     * @param billList                  当前店铺所有账单
     * @return
     */
    private BigDecimal sumBillAmountFromFinanceConfig(LocalDateTime endDate, List<SysAccountingProjectVO> filterAccountProjectList, List<SysBill> billList) {
        List<SysBill> filterBillList;
        if (Objects.nonNull(endDate)) {
            LocalDateTime lastDay = endDate.minusDays(1);
            filterBillList = billList.stream().filter(bill -> bill.getBillDate().isAfter(lastDay) && bill.getBillDate().isBefore(endDate)).toList();
        }else{
            filterBillList = billList;
        }
        BigDecimal amount = BigDecimal.ZERO;
        if (filterAccountProjectList.size() > 0) {
            // 获取所有符合条件的记账项目名称
            List<String> projectNameList = filterAccountProjectList.stream().map(SysAccountingProjectVO::getAccountingProjectName).toList();
            // 根据记账项目名称找到对应的账单
            filterBillList = filterBillList.stream().filter(bill -> projectNameList.contains(bill.getOriginalBillProject())).toList();
            if (filterBillList.size() > 0) {
                // 按照电商平台记账项目进行分组
                Map<String, List<SysBill>> groupBillList = filterBillList.stream().collect(Collectors.groupingBy(SysBill::getOriginalBillProject));
                SysAccountingProjectVO vo;
                for (String projectName : groupBillList.keySet()) {
                    // 找到对应的记账项目，通过【资金项目计算方向】进行计算
                    vo = filterAccountProjectList.stream().filter(item -> Objects.equals(item.getAccountingProjectName(), projectName)).findFirst().orElse(null);
                    if (Objects.nonNull(vo)) {
                        // 从资金项目类别2判断加减
                        Map<String, String> fundingProjects = vo.getFundingProjects();
                        if(fundingProjects.containsKey("资金项目类别2")){
                            String two = fundingProjects.get("资金项目类别2");
                            if(two.endsWith("+")){
                                amount = amount.add(groupBillList.get(projectName).stream().map(SysBill::getBillAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
                            }else if(two.endsWith("-")){
                                amount = amount.subtract(groupBillList.get(projectName).stream().map(SysBill::getBillAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
                            }else{
                                amount = amount.add(groupBillList.get(projectName).stream().map(SysBill::getBillAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
                            }
                        }
                    }
                }
            }
        }
        return amount;
    }

    /**
     *
     * 根据记账项目配置统计账单金额
     * @param endDate                   截止日期
     * @param filterAccountProjectList  符合条件的记账项目
     * @param billList                  当前店铺所有账单
     * @return
     */
    private BigDecimal sumBillAmountFromAccountingProject(LocalDateTime endDate, List<SysAccountingProjectVO> filterAccountProjectList, List<SysBill> billList) {
        BigDecimal amount = BigDecimal.ZERO;
        List<SysBill> filterBillList;
        if (Objects.nonNull(endDate)) {
            LocalDateTime lastDay = endDate.minusDays(1);
            filterBillList = billList.stream().filter(bill -> bill.getBillDate().isAfter(lastDay) && bill.getBillDate().isBefore(endDate)).toList();
        }else{
            filterBillList = billList;
        }
        if (filterAccountProjectList.size() > 0) {
            // 获取所有符合条件的记账项目名称
            List<String> projectNameList = filterAccountProjectList.stream().map(SysAccountingProjectVO::getAccountingProjectName).toList();
            // 根据记账项目名称找到对应的账单
            filterBillList = filterBillList.stream().filter(bill -> projectNameList.contains(bill.getOriginalBillProject())).toList();
            if (filterBillList.size() > 0) {
                amount = filterBillList.stream().map(SysBill::getBillAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            }
        }
        return amount;
    }
}
